Skip to content

fix(web): scope timeline minimap hover target to the side gutter#3869

Open
xxashxx-svg wants to merge 1 commit into
pingdotgg:mainfrom
xxashxx-svg:fix/minimap-hover-scoped-to-gutter
Open

fix(web): scope timeline minimap hover target to the side gutter#3869
xxashxx-svg wants to merge 1 commit into
pingdotgg:mainfrom
xxashxx-svg:fix/minimap-hover-scoped-to-gutter

Conversation

@xxashxx-svg

@xxashxx-svg xxashxx-svg commented Jul 10, 2026

Copy link
Copy Markdown

Fixes #3702

What

At non-default zoom (Cmd+Plus a few times) or at normal zoom with a wide sidebar / narrow window, the timeline minimap's hover target extends into the message text area: hovering body text triggers the minimap preview popover, the Copy button next to the timestamp can't appear, and text selection fights an invisible overlay.

Why it happens

The minimap is absolute left-0 on the full-width timeline viewport with a fixed hit strip (left-3 w-10, i.e. x = 12–52px) — and its w-18 wrapper is pointer-events-auto too, so the interactive region is really the leftmost ~72px. Meanwhile the message column is centered (max-w-3xl), so the side gutter between the viewport edge and the text is (viewportWidth − 768) / 2. Zooming in shrinks the effective CSS viewport width, and a wide sidebar shrinks the pane — both collapse that gutter toward zero while the fixed-px overlay stays put, landing it on top of the text. The pointer hit-test (resolveTimelineMinimapIndexFromPointer) only bounds the Y axis, so nothing stops it.

The Copy-button symptom is the same mechanism: the overlay swallows the pointer, so the message row's .group never enters :hover and group-hover:opacity-100 on the action row never fires.

Change

  • New pure helper resolveTimelineMinimapHitStripWidth(viewportWidth) in MessagesTimeline.logic.ts (same shape/placement as the existing resolveTimelineMinimapHasPersistentGutter): caps the strip's width to what actually fits between the viewport edge and the content column; returns 0 when there's no usable gutter.
  • The strip <button> takes that measured width (wide layouts keep the exact 40px they have today) and goes pointer-events-none at width 0.
  • The w-18 wrapper is now pointer-events-none, so only the width-capped strip captures the pointer. Hover-reveal still works — hovering the strip puts its ancestors in :hover, which is what the wrapper's hover:opacity-100 keys off — but it's now correctly scoped to the gutter. Keyboard navigation (focus + arrows) is unaffected.

Measurement reuses the existing ResizeObserver on the timeline viewport — no new observers or listeners.

Tests

Extended the existing logic-function test with the new helper: no-gutter (768/792 → 0, inert), partial gutter (820 → 14px strip), full gutter (872/1400 → 40px, today's behavior), and degenerate inputs. vp check and vp run typecheck pass; the full MessagesTimeline suite (12 tests) passes.

🤖 Generated with Claude Code


Note

Low Risk
Localized chat UI pointer-event and layout math with pure helpers and tests; no auth, data, or API changes.

Overview
Fixes timeline minimap interaction stealing pointer events from message text when zoom or a narrow pane shrinks the side gutter next to the centered column.

Adds resolveTimelineMinimapHitStripWidth to cap the minimap hover strip to the gutter (0 when there is no room, up to 40px when there is). The existing viewport ResizeObserver drives minimapHitStripWidth into TimelineMinimap, which applies that width on the strip button and uses pointer-events-none on the wrapper and on the strip when width is 0.

Wide layouts keep the previous 40px strip; partial gutters get a narrower target. Copy buttons, text selection, and hover on messages work again in the overlap case. Unit tests cover the new helper’s width cases.

Reviewed by Cursor Bugbot for commit f1264c1. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Scope timeline minimap hover target to the side gutter width

  • Adds resolveTimelineMinimapHitStripWidth in MessagesTimeline.logic.ts to compute the available gutter width, clamped to a maximum and returning 0 when no gutter exists.
  • The TimelineMinimap component now receives a hitStripWidth prop; its outer container is pointer-events-none and the inner button only receives pointer events when hitStripWidth > 0.
  • Behavioral Change: the minimap overlay no longer intercepts pointer events over the content column — clicks and hovers are limited to the side gutter area.

Macroscope summarized f1264c1.

The minimap overlay is anchored to the timeline viewport's left edge with
a fixed-width hover strip (left-3 w-10) and an always-interactive w-18
wrapper, while the message column is centered. Under browser zoom or a
narrow pane the side gutter between them collapses, so the fixed strip
lands on top of the message text: hovering body text pops the minimap
preview, the copy button next to the timestamp never reveals (the row's
group-hover can't fire while the overlay swallows the pointer), and text
selection fights the overlay.

Cap the strip's width to what actually fits between the viewport edge and
the content column, measured from the already-observed viewport width;
with no usable gutter the strip goes inert. The wrapper is now
pointer-events-none so only the width-capped strip captures the pointer
(hover reveal still works — hovering the strip puts its ancestors in
:hover). Wide layouts keep the exact 40px strip they have today.

Fixes pingdotgg#3702

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 5931f254-6bed-4b94-b237-ca7c89d67bfd

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Jul 10, 2026
@macroscopeapp

macroscopeapp Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

Self-contained UI fix with unit tests that adjusts pointer-event handling based on viewport width. The logic is clear and well-documented, but the author is not a frequent contributor to these files, warranting a quick human review.

You can customize Macroscope's approvability policy. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Timeline minimap hover target extends into text content area at non-default zoom levels

1 participant